﻿// -----------------------------------------------------------------------
// <copyright file="NeedsDisplay.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Cubezicles
{
    using System;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;

    // todo: make a similar display for an object/item that is currently selected in the 3d world???

    /// <summary>
    /// Manages the display of the needs for the currently selected employee
    /// </summary>
    public class NeedsDisplay : DrawableGameComponent
    {
        // Texture that we'll stretch out and re-color to display the NeedsMeter.
        private Texture2D dot;

        // Texture for the interface background and mood and the employee body
        private Texture2D bg, mood, body;

        //Texture for buttons
        Texture2D btn;

        // - Parameters for drawing lines of text
        private float StatusX; // Set in draw

        // Distance from left side of the screen where the meter starts
        private float MeterX; // Also set in draw

        // Distance from the top of each line where the meter starts
        private const float MeterOffset = 6.0f;

        // Height of each meter
        private const float MeterHeight = 12.0f;
        
        // the height of a line in pixels
        private const int LineHeight = 20;

        // Current Employee format
        const string employeeFormat = "Current Employee: {0}";

        // Get the active employee from the Game1
        private Employee emp { get { return game1.CurrentEmployee; }}

        // Get the Game1 object stored by the base class
        private Game1 game1 { get { return (Game1)Game; } }

        public NeedsDisplay(Game1 game) : base(game) { this.DrawOrder = (int)Game1.DisplayOrder.UI; }

        protected override void LoadContent()
        {
            dot = Game.Content.Load<Texture2D>("Textures/dot");
            bg = Game.Content.Load<Texture2D>("UI/workerstatbg");
            mood = Game.Content.Load<Texture2D>("UI/mood");
            btn = Game.Content.Load<Texture2D>("UI/buttons");
            base.LoadContent();
        }

        UI.Button control;
        public override void Draw(GameTime gameTime)
        {
            // Get the screen width and height
            int screenH = game1.screenH;
            int screenW = game1.screenW;

            StatusX = screenW - bg.Width + 35;
            MeterX = StatusX + 80;

            // If no employee is selected, this component does nothing
            if (emp == null)
            {
                return;
            }
            
            game1.SpriteBatch.Begin();

            // The line (from top of screen) to start writing at
            float currY = screenH - 160; // mmmm, curry 

            // Draw the background and Avatar's mood
            game1.SpriteBatch.Draw(bg, new Vector2(screenW - bg.Width, currY), Color.White);


            // Use the colors calculated by the employee's overallMood
            // to determine the background color for the avatar profile pic thingy
            game1.SpriteBatch.Draw(mood, new Vector2(screenW - mood.Width, currY-5), determineColor(emp.OverallMood));

            //Draw the Employee picture
            Texture2D face = emp.GetFace();
            body = emp.GetBody();
            int headw = 50, bodyw = 60, aviY = (int)currY - 10;
            float proportion = 1.2f;
            game1.SpriteBatch.Draw(face, new Rectangle(screenW - bodyw + (bodyw - headw) / 2 - 30, aviY, headw, headw), Color.White);
            game1.SpriteBatch.Draw(body,
                new Rectangle(screenW - bodyw - 30, aviY - 5 + headw, bodyw, (int) (bodyw*proportion)), 
                new Rectangle(0,0, body.Width, (int)(body.Width *proportion)),  
            Color.White);

            // Display the employee's name
            //var employeeMsg = string.Format(employeeFormat, game1.CurrentEmployee.Name);
            string employeeMsg = game1.CurrentEmployee.Name;
            game1.SpriteBatch.DrawString(game1.Fonts["status"], employeeMsg,
            new Vector2(screenW - 75, screenH - 80), game1.UIblue);

            //currY += LineHeight;

            //currY += LineHeight;
            currY += 2;
            currY = DrawNeed(emp.MoodLevels.hunger, "Hunger", currY);
            currY = DrawNeed(emp.MoodLevels.fun, "Fun", currY);
            currY = DrawNeed(emp.MoodLevels.energy, "Energy", currY);
            currY = DrawNeed(emp.MoodLevels.bladder, "Bladder", currY);
            currY = DrawNeed(emp.MoodLevels.focus, "Focus", currY);
            int x = 10;

            //--- Get back to work button ---//
            if (emp.CurrentState != NeedsManager.State.Working) //Employee.State.Working)
            {
                control = new UI.Button()
                {
                    Texture = btn,
                    font = game1.Fonts["info"],
                    text = "Get back to work!",
                    xpos = screenW - 140,
                    ypos = screenH - 55,
                    OnClick = (cont) => emp.GetBackToWork()
                };

                // If the employee is at home, cannot force them to get back to work
                if (emp.CurrentState == NeedsManager.State.AtHome)
                {
                    control.Active = false;
                }

                control.Update(GraphicsDevice.Viewport, game1.ms, game1.oldms);
                control.Draw(game1.SpriteBatch, GraphicsDevice.Viewport);

                x += 132;
            }

            // Draw Status
            var statusString = "Status: " + game1.CurrentEmployee.GetStateString();
            game1.SpriteBatch.DrawString(game1.Fonts["status"], statusString,
            new Vector2(screenW - game1.Fonts["status"].MeasureString(statusString).X - x, screenH - 50), game1.UIblue);
            //^'s a good example of right aligned text.

            if (game1.pathON) 
                emp.writeGraph(game1.SpriteBatch);
            game1.SpriteBatch.End();

 	        base.Draw(gameTime);
        }


        /// <summary>
        /// Draw the name and meter for a particular need.
        /// If the need is still at a "good" level, will draw meter in green, otherwise meter will be red.
        /// </summary>
        /// <param name="need">the need float variable</param>
        /// <param name="needName">Name of the need (to write to the screen)</param>
        /// <param name="y">Y position of cursor</param>
        /// <returns>New Y position for cursor</returns>
        private float DrawNeed(float need, string needName, float y)
        {
            var statNameStart = new Vector2(StatusX, y);

            // Rectangle outlining the health meter.
            var meterRect = new Rectangle((int)MeterX, (int)(y + MeterOffset),
                                          (int)(100 * need), (int)MeterHeight);

            var color = determineColor(need);

            game1.SpriteBatch.DrawString(game1.Fonts["needs"], needName + ": ", statNameStart, color);
            game1.SpriteBatch.Draw(dot, meterRect, color);

            return y + LineHeight;
        }
        
        /// <summary>
        /// Determine the color to draw a need based on its level
        /// Green is full, Red is empty, and gradually changes in between
        /// Reference: http://www.xtremevbtalk.com/showthread.php?t=319701
        /// </summary>
        /// <param name="level">the variable (mood or need) that we are determining a color for</param>
        /// <returns>the color to use when drawing the variable level</returns>
        public static Color determineColor(float level)
        {
            // we only need red and green to get red, yellow, green, and between colors
            float r = 1f;
            float g = 0f;

            if (level < .5)      // if the mood is below 50%
            {
                r = 1f;                  // Red is at 100% for red and yellow
                g = level / .5f;   // Green should increase from 0 to 100% over mood 0 to 50%                        
            }
            else // Else health is 50% or greater, diminish Red, leaving green
            {
                r = (1f - level) / .5f;    // from 50% to 100% mood, Red should decrease from 100% to 0%
                g = 1f;                  // Green stays at 100%
            }

            return new Color(r, g, 0f);
        }

        #region pathfinding

        //Draw Graph (test for pathfinding)
        public void drawGraph()
        {
            int nCount = 0, eCount = 0;
            foreach (Node n in game1.gra.nodes)
            {
                game1.SpriteBatch.Draw(dot, new Rectangle((int)n.pos.X * 4 + 200, (int)n.pos.Z * 4 + 400, 4, 4), Color.Red);
                nCount++;
            }

            foreach (Edge e in game1.gra.edges)
            {
                DrawLine(dot, new Vector2(e.n1.pos.X * 4 + 200, e.n1.pos.Z * 4 + 400), new Vector2(e.n2.pos.X * 4 + 200, e.n2.pos.Z * 4 + 400), Color.Yellow);
                eCount++;
            }

            var where = new Vector2(210, 105 + 120);
            var what = "#Edges:" + eCount + " # Nodes: " + nCount;
            game1.SpriteBatch.DrawString(game1.Fonts["status"], what, where, Color.White);
        }

        void DrawLine(Texture2D spr, Vector2 a, Vector2 b, Color col)
        {
            Vector2 Origin = new Vector2(0.5f, 0.0f);
            Vector2 diff = b - a;
            float angle;
            Vector2 Scale = new Vector2(1.0f, diff.Length() / spr.Height);

            angle = (float)(Math.Atan2(diff.Y, diff.X)) - MathHelper.PiOver2;

            game1.SpriteBatch.Draw(spr, a, null, col, angle, Origin, Scale, SpriteEffects.None, 1.0f);
        }
        #endregion
    }
}
